﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;
using System.IO;

namespace DCT.AutoUpdate.Code.Config
{
    public class AutoUpdateXmlConfigParser : IConfigParser
    {
        private static string DEFAULT_ROOT_TAG = "root";

        private string rootTag = DEFAULT_ROOT_TAG;
        private XmlNode rootNode = null;
        private KeyValueCache<object> cache = new KeyValueCache<object>();

        public string RootTag { get { return this.rootTag; } set { this.rootTag = value; } }
        public XmlNode RootNode { get { return this.rootNode; } }

        public AutoUpdateXmlConfigParser()
        {
            this.rootNode = XmlUtility.CreateEmptyXmlDocument(this.RootTag).DocumentElement; 
        }

        public IConfigParser Load(object config)
        {
            if (config == null || !(config is string))
            {
                throw new ArgumentException("config不能为空，且必须为字符串");
            }
            this.cache.Reset();
            this.rootNode = XmlUtility.Load(config.ToString()).DocumentElement;
            return this;
        }

        public IConfigParser Clear()
        {
            this.cache.Reset();
            this.rootNode.RemoveAll();
            return this;
        }

        public string ParseToString()
        {
            return XmlUtility.DEFAULT_XML_DECLARATION + this.rootNode.OuterXml;
        }

        public IEnumerable<KeyValuePair<string, string>> GetKV(string key)
        {
            /*<key>
             *  <item1>valu1</item1>
             *  <item1>valu1</item1>
             *</key> 
            */

            string xpath = key;
            XmlNode xmlNode = cache.GetValue(xpath, xpathKey =>
            {
                return this.rootNode.SelectSingleNode(xpathKey);
            }) as XmlNode;

            if (xmlNode != null)
            {
                foreach (XmlNode item in xmlNode.ChildNodes)
                {
                    if (item.NodeType == XmlNodeType.Element)
                    {
                        yield return new KeyValuePair<string, string>(item.Name, XmlUtility.GetNodeInnerText(item));
                    }
                }
            }
        }

        public IEnumerable<IEnumerable<KeyValuePair<string, string>>> GetListKV(string key)
        {
            /*
    <downloads>
        <item>
            <url>http://localhost:3643/package/1.0/accessibilitycpl.dll</url>
        </item>
        <item>
            <url>http://localhost:3643/package/1.0/ACCTRES.dll</url>
        </item>
        <item>
            <url>http://localhost:3643/package/1.0/acledit.dll</url>
        </item>
        <item>
            <url>http://localhost:3643/package/1.0/aclui.dll</url>
        </item>
        <item>
            <url>http://localhost:3643/package/1.0/acppage.dll</url>
        </item>
        <item>
            <url>http://localhost:3643/package/1.0/acproxy.dll</url>
        </item>
    </downloads>
             */
            string xpath = key;
            XmlNode xmlNode = cache.GetValue(xpath, xpathKey =>
            {
                return this.rootNode.SelectSingleNode(xpathKey);
            }) as XmlNode;

            if (xmlNode != null)
            {
                foreach (XmlNode item in xmlNode.ChildNodes)
                {
                    if (item.NodeType == XmlNodeType.Element)
                    {
                        Dictionary<string, string> kv = new Dictionary<string, string>();

                        foreach (XmlNode kvChildNode in item.ChildNodes)
                        {
                            kv[kvChildNode.Name] = XmlUtility.GetNodeInnerText(kvChildNode);
                        }

                        yield return kv;
                    }
                }
            }
        }

        public IEnumerable<string> GetListVal(string key)
        {
            /*
    <whatsnew>
        <item>
            <![CDATA[ 
            修正xxxxbug
            ]]>
        </item>
        <item>
            <![CDATA[ 
            提高性能
            ]]>
        </item>
    </whatsnew>*/
            string xpath = key;
            XmlNode xmlNode = cache.GetValue(xpath, xpathKey =>
            {
                return this.rootNode.SelectSingleNode(xpathKey);
            }) as XmlNode;

            if (xmlNode != null)
            {
                foreach (XmlNode item in xmlNode.ChildNodes)
                {
                    if (item.NodeType == XmlNodeType.Element)
                    {
                        yield return XmlUtility.GetNodeInnerText(item);
                    }
                }
            }
        }

        public string GetVal(string key, string defaultVal)
        {
            //<key>value</key>
            string xpath = key;
            return cache.GetValue(xpath, xpathKey =>
            {
                return XmlUtility.GetNodeInnerText(this.rootNode.SelectSingleNode(xpathKey), defaultVal);
            }) as string;
        }

        /*  此项目暂时都不需要set，都不实现 */
        public void SetKV(string key, IEnumerable<KeyValuePair<string, string>> kv)
        {
            throw new NotImplementedException();
        }

        public void SetListKV(string key, IEnumerable<IEnumerable<KeyValuePair<string, string>>> kvList)
        {
            throw new NotImplementedException();
        }

        public void SetListVal(string key, IEnumerable<string> listVal)
        {
            throw new NotImplementedException();
        }

        public void SetVal(string key, string val)
        {
            throw new NotImplementedException();
        }

        public static string GetRealPath(string pathInConfig) {
            return pathInConfig.Replace("#appfolder#", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
        }
    }
}
